/*
  FileName : USB_HostApp.c
  Description : 
          This is the USB_Host USBD unit used to Handler mass-storage class.
  Created on 2007.9.17 by ZZP.

  Revision History:
    2008.11.19: 修改成 GPS 中的 USB，功能：
	  1、插上 MASS 类的 USB device 时检测其文件结构，符合特征则认为要更新GPS数据库；
	  2、检测文件日期：如果比当前文件新则可用；
*/

/*
  关于内部Hub：
    用作带CE等操作系统的系统中时，需要软件实现对Hub命令的响应。
	在本应用中，没有使用CE，直接操纵寄存器即可。
*/


#include <stdlib.h>//包含 srand() 定义

#include "DSP281x_Device.h"

//Test only
extern volatile Uns TmTestLong;

//数据库文件的FAT：
//----------------------------------------
#ifdef __cplusplus 
#pragma DATA_SECTION("UserDataFile") 
#else 
#pragma DATA_SECTION(FatBuf,"UserDataFile");
#endif
LgUns FatBuf[16384];//LgUns FatBuf[256];

//----------------------------------------
#ifdef __cplusplus 
#pragma DATA_SECTION("UserDataFile") 
#else 
#pragma DATA_SECTION(FatBuf2,"UserDataFile");
#endif
LgUns FatBuf2[256]; 


//----------------------------------------
#ifdef __cplusplus 
#pragma DATA_SECTION("UserDataFile") 
#else 
#pragma DATA_SECTION(FileBuf,"UserDataFile");
#endif
Uns FileBuf[4096];

//----------------------------------------
#ifdef __cplusplus 
#pragma DATA_SECTION("UserDataFile") 
#else 
#pragma DATA_SECTION(UsbDataBuf,"UserDataFile");
#endif
Uns UsbDataBuf[32768];

//----------------------------------------
#ifdef __cplusplus 
#pragma DATA_SECTION("UserDataFile") 
#else 
#pragma DATA_SECTION(CheckBuf,"UserDataFile");
#endif
Uns CheckBuf[32768]; 

//----------------------------------------
#ifdef __cplusplus 
#pragma DATA_SECTION("UserDataFile") 
#else 
#pragma DATA_SECTION(ABuf,"UserDataFile");
#endif
Uns ABuf[4096];

//----------------------------------------
#ifdef __cplusplus 
#pragma DATA_SECTION("UserDataFile") 
#else 
#pragma DATA_SECTION(BiosFileBuf,"UserDataFile");
#endif 
Uns BiosFileBuf[MAX_BIOS_BUF_SIZE];


DATA_BASE_INFO UsbFile;


//检测USB设备上是否包含 GPS库文件、BIOS软件文件
//reflect on MyInfo.ErrF
//Including Saving DataBase function
void HcApp_StatusHandler(void)
{
  Uns i, seed, tmp, NorSecCnt;
  LgUns Val, Offset;

  Hc_GetInternalPortStatus(2);
  if ((PortStsData2.Sts.bit.ConnectSts == 0) || (PortStsData2.StsChange.bit.ConnectStsChange == 0))
  {
    if (MyInfo.DevConnected)
	  DBG_ExportInfo(SYS_INFO_WORK_FLAG, NULL);
    MyInfo.DevConnected = 0;
	MyInfo.UsbDevF = 0;
	if (MyInfo.HcWorkF == 1)
	  MyInfo.HcWorkF = 2;
    return;
  }
  //增加 50ms 延时再判断连接状态。否则在拔出 USB 设备时会误检测成插入。
  for (i = 0; i < 50000; i++)
    asm("  RPT #150 || NOP");
  Hc_GetInternalPortStatus(2);
  if (PortStsData2.Sts.bit.ConnectSts == 0)
  {
    if (MyInfo.DevConnected)
	  DBG_ExportInfo(SYS_INFO_WORK_FLAG, NULL);
    MyInfo.DevConnected = 0;
	MyInfo.UsbDevF = 0;
	if (MyInfo.HcWorkF == 1)
	  MyInfo.HcWorkF = 2;
    return;
  }
  
  if (MyInfo.DevConnected)
    return;
  MyInfo.DevConnected = 1;
  Hc_XDevInfo.CtrlXferOK = 0;
  MyInfo.ErrF = USB_SAVING_DB;
  OFF_USBD_LED;
  MyInfo.UsbDevF = 1;
  Hc_EnumDevice();
  if (Hc_XDevInfo.DevOK == 0)
  {
    Hub_ClearPortFeature(2, C_PORT_CONNECTION, 0, 2, PORT_TYPE_INTERNAL_HUB);
	MyInfo.ErrF = USB_DEV_ERR;
    return;
  }

  seed = 0xFFFF;
  srand(seed);
  i = rand();
  Val = ((LgUns)i << 8);
  Val += 0x81000008;
  HcCBW.dCBW_Tag = Val;
  Hc_XDevInfo.BulkInTog = PID_DATA0;
  Hc_XDevInfo.BulkOutTog = PID_DATA0;
  
  DBG_ExportInfo(SYS_INFO_USB_FLAG, NULL);

  MyInfo.HcWorkF = 1;
  
  //MyInfo.WorkSts = WORK_STATUS_HOST_USB;
  tmp = HcApp_GetDeviceInfo();
  if (Hc_XDevInfo.DevOK && (tmp == 1))
  {
    tmp = HcApp_CheckGpsDataFile();
	if (tmp)
	{
	  MyInfo.FormatF = 1;

	  Offset = (LgUns)UsbFile.FileClusCnt * hbpb.TotBytesPerClus;
	  if (Offset <= (MyInfo.XFlashSize >> 1)){
	    NorSecCnt = Offset >> 17;// NOR Flash sector-size: 128KBytes
	    NorSecCnt++;
		Offset = 0;
		for (i = 0; i < NorSecCnt; i++){
	      lld_SectorEraseOp((Uns *)S29G_BASE_ADDR, Offset);
		  Offset += 0x10000L;//One sector : 64KWord
		}
	  }
	  else
	    lld_ChipEraseOp((Uns *)S29G_BASE_ADDR);
	  MyInfo.FormatF = 0;
	  if (HcApp_SaveDataBase())
      {
	    DBG_ExportInfo(USB_INFO_UPDATE_OK, NULL);

		MyInfo.ErrF = USB_SAVE_DB_OK;//OK
	  }
      else
	    MyInfo.ErrF = USB_SAVE_DB_ERR;
	}
	else
	  MyInfo.ErrF = USB_NO_DB;

	if (HcApp_CheckBackupFile())
	  HcApp_SaveDB2Usb();
	/*if (MyInfo.EnWrBios)
	{
	  if (HcApp_CheckBiosFile())
	  {
	    if (ScanHexData(BiosFileBuf, ((UsbFile.FileSize + 1) >> 1), BiosFileBuf))
		  ;
	  }
	}*/
  }
  else
    MyInfo.ErrF = USB_DEV_ERR;

  if (MyInfo.ErrF != USB_SAVE_DB_OK)
    DBG_ExportInfo(USB_INFO_UPDATE_ERR, NULL);

  //MyInfo.HcWorkF = 0;
  //MyInfo.WorkSts = WORK_STATUS_NORMAL;
}

void HcApp_Interrupt_Isr(void)
{
  LgUns temp, Sts;

  temp = Hal_HostRead32bitReg((Uns *)&(Hc_InterruptRegs.HcIntRegLo));
  Sts = temp & IntrReg_Mask;
  //Sts |= IntrReg_ResetValue;
  Hal_HostWrite32bitReg((Uns *)&(Hc_InterruptRegs.HcIntRegLo), Sts);

  /*if (temp & 0x0020)//HCSUSP
  {
    //HcApp_GetPortStatus();
  }*/
  if (temp & 0x0100)//ATL_IRQ
  {
    Sts = Hal_EHCIRead32bitReg((Uns *)&(EHCI_OpRegs.ATL_DoneMapRegLo));
    if (Sts & 0x01)
	{
	  //ReadPTD0:
      Hc_XDevInfo.ATLBufDone = 1;
	  Hal_ReadPTD(0, 0);
	}
  }
}

void HcApp_GetPortStatus(void)
{
  LgUns temp;

  temp = Hal_EHCIRead32bitReg((Uns *)&(EHCI_OpRegs.PortSc1RegLo));
  if (temp & 0x40)//02)//Connect status changed
  {
    if (temp & 0x01)
	{
	  if (!Hc_XDevInfo.Connected)
	  {
	    Hc_XDevInfo.Connected = 1;
		Hc_XDevInfo.State = HC_STATE_ENUM;
	  }
	}
	else
	{
	  if (Hc_XDevInfo.Connected)
	  {
	    Hc_XDevInfo.Connected = 0;
		Hc_XDevInfo.State = HC_STATE_IDLE;
	  }
	}
  }
}

Uns HcApp_GetDeviceInfo(void)
{
  Uns i, j, k, OK;
  
  if (!Hc_XDevInfo.DevOK)
    return (0);
  for (i = 0; i < 60000; i++)
	asm(" RPT #250 || NOP");
  Hc_XDevInfo.Sec0LBA = 0;
  HDInfo.DiskSz = 0;
  for (j = 0; j < 20; j++){
    MB_TestUnit(0);
	for (i = 0; i < 60000; i++){
	  asm(" RPT #250 || NOP");
	  asm(" RPT #250 || NOP");
	  asm(" RPT #250 || NOP");
	  asm(" RPT #250 || NOP");
	}
  }
  Hc_XDevInfo.MaxLUN = 1;
  OK = 0;
  for (j = 0; j < 3; j++)
  {
    for (i = 0; i < Hc_XDevInfo.MaxLUN; i++)
    {
      if (MB_Inquiry(i))
        MB_RequestSense(i);
    }
    for (i = 0; i < Hc_XDevInfo.MaxLUN; i++)
    {
      if(MB_ReadFormatCapacity(i))
      {
        MB_RequestSense(i);
		MB_TestUnit(i);
	  }
    }
    for (i = 0; i < Hc_XDevInfo.MaxLUN; i++)
    {
      k = MB_ReadCapacity(i);
      if (k)
	  {
        MB_RequestSense(i);
		MB_TestUnit(i);
	  }
      else if (HDInfo.DiskSz > 983040)//> 480MB
      {
        Hc_XDevInfo.CurrLUN = i;
        OK = 1;
        break;
      }
    }
    if (OK)
      break;
  }
  if (OK)
  {
	MB_TestUnit(0);
    for (i = 0; i < 5; i++)
    {
      //if (!MB_TestUnit(Hc_XDevInfo.CurrLUN))
      {
        //for (j = 0; j < 1; j++)
        {
          k = MB_ReadSec0(Hc_XDevInfo.CurrLUN);
          /*if (k == 0xFF)
          {
            if ((HDInfo.DiskSz > 0) && (HDInfo.DiskSz < 8519680L))
              return (1);//CF Card
            Hc_XDevInfo.DevOK = 0;
            return (0);
          }
          else*/ if (k > 0)
          {
            OK++;
            //break;
          }
          else
		  {
            MB_RequestSense(Hc_XDevInfo.CurrLUN);
			MB_TestUnit(Hc_XDevInfo.CurrLUN);
		  }
        }
        if (OK)
          break;
      }
      //else
      //  MB_RequestSense(Hc_XDevInfo.CurrLUN);
    }
  }
  if (!OK)
  {
    Hc_XDevInfo.DevOK = 0;
    return (0);
  }
  if (OK == 1)
  {
    if ((HDInfo.DiskSz > 0))// && (HDInfo.DiskSz < 8519680L))
      return (1);//CF Card
    Hc_XDevInfo.DevOK = 0;
    return (0);
  }
  /*if (HDInfo.PartitionCnt == 1)
  {
    i = HDInfo.PartitionIndex;
    Hc_XDevInfo.Sec0LBA = HDInfo.PartitionInfo[i].RelativeSec;
    for (i = 0; i < 3; i++)
    {
      k = MB_ReadSec0(Hc_XDevInfo.CurrLUN);
      if (!k)
	  {
        MB_RequestSense(Hc_XDevInfo.CurrLUN);
		MB_TestUnit(Hc_XDevInfo.CurrLUN);
	  }
      else
        break;
    }
    if (!k)
    {
      Hc_XDevInfo.DevOK = 0;
      return (0);
    }
  }*/

  hbpb.TotSec32 = Host_DataBuf[16] + ((unsigned long)Host_DataBuf[17] << 16); 
  if (hbpb.BytesPerSec != 0x200)//512
    OK = 0;
  else if (hbpb.NumFATs != 2)
    OK = 0;
  else if (hbpb.SecPerClus > 64)
    OK = 0;
  else if (hbpb.RootClus > 2)
    OK = 0;
  else if (hbpb.RsvdSecCnt > 40)
    OK = 0;
  else if (hbpb.RootEntCnt != 0)
    OK = 0;  
  else if (hbpb.RootDirSectors != 0)
    OK = 0;
  else if (hbpb.FirstDataSector != hbpb.RsvdSecCnt + 
                                   (hbpb.NumFATs * hbpb.FATSz32) + 
                                   hbpb.RootDirSectors)
    OK = 0;
  else if (hbpb.FirstFATSector != hbpb.RsvdSecCnt + hbpb.RootDirSectors)
    OK = 0;
  //if (ModeSenseCmd())
  //  RequestSenseCmd();
  if (!OK)
  {
    Hc_XDevInfo.DevOK = 0;
    return (0);
  }
  
  /*if (hbpb.SecPerClus > 8)
    return (2);//not a cf card
  else//CF Card*/
    return (1);
}

//从文件 FAT 表查找连续簇数量
Uns GetContinuousFat(LgUns *Fats, Uns TotCnt, Uns CurrPos, Uns MaxCnt)
{
  Uns Cnt, Pos;
  LgUns Prefix;

  Cnt = 1;
  Pos = CurrPos;
  Prefix = Fats[Pos++];
  while (Pos++ < TotCnt)
  {
    if (Fats[Pos] == Prefix + 1)
	{
	  Cnt++;
	  Prefix++;
	  if (Cnt >= MaxCnt)
	    return (MaxCnt);
	}
	else
	  return (Cnt);
  }
  return (Cnt);
}

//检测数据库文件：
/*
  1、数据库文件必须位柯枷拢�
  2、数据库文件名采用短文件名(8.3格剑�
  3、文件512字节为文件头，有CRC；
  4、文件结尾512字节为文件尾，有CRC；
  5、文件占用整数个簇，不足部分填充0；
  6、文件名称：YYYYMMDD.GPS；
*/

Uns HcApp_CheckGpsDataFile(void)
{
  LgUns tmp, Sec, FirstClus;
  Uns i, j, k, Cnt, /*OK,*/ CRC, Buf[8];

  FirstClus = 2;//根目录
  Cnt = FAT32_GetFileClusters(USB_CF, (BPB_INFO *)&hbpb, FatBuf2, FirstClus);
  for (i = 0; i < Cnt; i++)
  {
    //FileNames:
    Sec = hbpb.FirstDataSector + (FatBuf2[i] - 2) * hbpb.SecPerClus;
	MB_TestUnit(0);
	MB_ReadCF(FileBuf, Sec, hbpb.SecPerClus);
	for (j = 0; j < (hbpb.TotBytesPerClus >> 1); j += 16)
	{
	  if ((FileBuf[j] & 0xFF) == 0x00)
	    break;
	  if (((FileBuf[j] & 0xFF) == 0x2E) || ((FileBuf[j] & 0xFF) == 0xE5))
	    continue;
	  for (k = 0; k < 5; k++)
      {
        UsbFile.FileName[k << 1] = (FileBuf[j + k] & 0xFF);
        UsbFile.FileName[(k << 1) + 1] = FileBuf[j + k] >> 8;
      }
      UsbFile.FileName[10] = FileBuf[j + 5] & 0xFF;
	  if ((UsbFile.FileName[8] == 'G') && (UsbFile.FileName[9] == 'P') && (UsbFile.FileName[10] == 'S'))//
	  {
	    UsbFile.FileSize = FileBuf[j + 14] + ((LgUns)FileBuf[j + 15] << 16);
		if (UsbFile.FileSize + 0x20000L > MyInfo.XFlashSize)
		  return (0);
		for (k = 0; k < 8; k++)
		  Buf[k] = UsbFile.FileName[k];
		if (!CheckTimeValid(TIME_SRC_FILENAME, Buf))
		  return (0);
		memcpy((void *)&UsbFile.Time, Buf, 6);
		/*OK = 0;
		if (UsbFile.Time.Year > MyInfo.DataBaseTime.Year)
		  OK = 1;
		else if (UsbFile.Time.Year == MyInfo.DataBaseTime.Year)
		{
		  if (UsbFile.Time.Month > MyInfo.DataBaseTime.Month)
		    OK = 1;
		  else if (UsbFile.Time.Month == MyInfo.DataBaseTime.Month)
		    if (UsbFile.Time.Date >= MyInfo.DataBaseTime.Date)
		      OK = 1;
		}
		if (!OK)
		  return (0);*/
		//Get FATs:
        FirstClus = ((LgUns)FileBuf[j + 10] << 16) + FileBuf[j + 13];
        UsbFile.FileClusCnt = FAT32_GetFileClusters(USB_CF, (BPB_INFO *)&hbpb, FatBuf, FirstClus);
		Sec = UsbFile.FileClusCnt;
		Sec *= hbpb.TotBytesPerClus;
		if ((UsbFile.FileClusCnt < 1) ||
		    (UsbFile.FileSize > Sec) ||
		    (Sec > hbpb.TotBytesPerClus + UsbFile.FileSize))
		  return (0);

        //Head checking:
		Sec = hbpb.FirstDataSector + (FatBuf[0] - 2) * hbpb.SecPerClus;
		MB_TestUnit(0);
        MB_ReadCF(ABuf, Sec, 1);
		if ((ABuf[0] != GPS_FILE_ID_LO) || (ABuf[1] != GPS_FILE_ID_HI))
	      return (0);
		CRC = Calc_CRCWord(ABuf + 2, 16, 506);
		if (CRC != ABuf[255])
		  return (0);
		memcpy(Buf, ABuf + 2, 4);
		UsbFile.Time.Second = ABuf[2] & 0xFF;
        UsbFile.Time.Minute = ABuf[2] >> 8;
		UsbFile.Time.Hour = ABuf[3] & 0xFF;
		UsbFile.Time.Date = ABuf[3] >> 8;
		UsbFile.Time.Month = ABuf[4] & 0xFF;
		UsbFile.Time.Year = (ABuf[4] >> 8) + (ABuf[5] << 8);
		memcpy((void *)&UsbFile.Version, ABuf + 6, 6);
		UsbFile.StCnt = ABuf[12] + ((LgUns)ABuf[13] << 16);
		if (UsbFile.StCnt == 0)
		  return (0);

		/*
		UsbFile.RegCnt = ABuf[21];
		Sec = S29G_GetUnitQty(1, UsbFile.StCnt);
		tmp = S29G_GetUnitQty(0, UsbFile.StCnt);
		k = S29G_GetUnitQty(0, UsbFile.RegCnt);
		Sec <<= 5;// x32
		tmp <<= 8;//tmp <<= 7;
		tmp += (k << 8);
		UsbFile.RdCnt = ABuf[22];
		k = S29G_GetUnitQty(2, UsbFile.RdCnt);
		tmp += (k << 4);

		UsbFile.StAuxCnt = ABuf[23];
		k = S29G_GetUnitQty(3, UsbFile.StAuxCnt);
		tmp += (k << 6);

		Sec += tmp;
		*/
		//new database(WFL):RegCnt is the 56th and 57th byte
		//new database:(offset:50)RdCnt:2 Bytes;StCnt:4 Bytes;RegCnt:2 Bytes;QHCnt:2 Bytes;
		Sec = S29G_GetUnitQty(3, UsbFile.StCnt);//a multiple of 8
		Sec <<= 6;// x64
		UsbFile.RdCnt = ABuf[25];
		tmp = S29G_GetUnitQty(3, UsbFile.RdCnt);//a multiple of 8
		tmp <<= 6;// x64
		Sec += tmp;
		UsbFile.RegCnt = ABuf[28];
		tmp = S29G_GetUnitQty(3, UsbFile.RegCnt);//a multiple of 8
		tmp <<= 6;// x64
		Sec += tmp;
		UsbFile.QieHuanCnt = ABuf[29];
		tmp = S29G_GetUnitQty(3, UsbFile.QieHuanCnt);//a multiple of 8
		tmp <<= 6;// x64
		Sec += tmp;
		//1024 = head + tail

		if ((UsbFile.FileSize != Sec + 1024) && (UsbFile.FileSize != Sec + hbpb.TotBytesPerClus + 1024))
		  return (0);//WFL: the time fine an error of DataBase here
		//Tail checking:只读最后一个扇区
        Sec = hbpb.FirstDataSector + (FatBuf[UsbFile.FileClusCnt - 1] - 2) * hbpb.SecPerClus;
		k = UsbFile.FileSize >> 9;// div 512
		k = k % hbpb.SecPerClus;
		if (!k)
		  Sec += (hbpb.SecPerClus - 1);
		else
		  Sec += (k - 1);
		//Sec += (hbpb.SecPerClus - 1);
		MB_TestUnit(0);
        MB_ReadCF(ABuf, Sec, 1);
		if ((ABuf[0] != GPS_TAIL_ID_LO) || (ABuf[1] != GPS_TAIL_ID_HI))
		  return (0);
		CRC = Calc_CRCWord(ABuf + 2, 16, 506);
		if (CRC != ABuf[255])
		  return (0);
		for (k = 0; k < 3; k++)
		{
		  if (ABuf[2 + k] != Buf[k])
		    return (0);
		}
		if ((ABuf[5] & 0xFF) != (Buf[3] & 0xFF))
		  return (0);
		/*for (k = 0; k < 6; k++)
		{
		  if (ABuf[6 + k] != UsbFile.Version[k])
		    return (0);
		}*/
		if (ABuf[12] + ((LgUns)ABuf[13] << 16) != UsbFile.StCnt)
		  return (0);

        return (UsbFile.StCnt & 0xFFFF);
	  }
	}
  }
  return 0;
}
Uns HcApp_CheckGpsDataFile_backup(void)
{
  LgUns tmp, Sec, FirstClus;
  Uns i, j, k, Cnt, /*OK,*/ CRC, Buf[8];

  FirstClus = 2;//根目录
  Cnt = FAT32_GetFileClusters(USB_CF, (BPB_INFO *)&hbpb, FatBuf2, FirstClus);
  for (i = 0; i < Cnt; i++)
  {
    //FileNames:
    Sec = hbpb.FirstDataSector + (FatBuf2[i] - 2) * hbpb.SecPerClus;
	MB_TestUnit(0);
	MB_ReadCF(FileBuf, Sec, hbpb.SecPerClus);
	for (j = 0; j < (hbpb.TotBytesPerClus >> 1); j += 16)
	{
	  if ((FileBuf[j] & 0xFF) == 0x00)
	    break;
	  if (((FileBuf[j] & 0xFF) == 0x2E) || ((FileBuf[j] & 0xFF) == 0xE5))
	    continue;
	  for (k = 0; k < 5; k++)
      {
        UsbFile.FileName[k << 1] = (FileBuf[j + k] & 0xFF);
        UsbFile.FileName[(k << 1) + 1] = FileBuf[j + k] >> 8;
      }
      UsbFile.FileName[10] = FileBuf[j + 5] & 0xFF;
	  if ((UsbFile.FileName[8] == 'G') && (UsbFile.FileName[9] == 'P') && (UsbFile.FileName[10] == 'S'))//
	  {
	    UsbFile.FileSize = FileBuf[j + 14] + ((LgUns)FileBuf[j + 15] << 16);
		if (UsbFile.FileSize + 0x20000L > MyInfo.XFlashSize)
		  return (0);
		for (k = 0; k < 8; k++)
		  Buf[k] = UsbFile.FileName[k];
		if (!CheckTimeValid(TIME_SRC_FILENAME, Buf))
		  return (0);
		memcpy((void *)&UsbFile.Time, Buf, 6);
		/*OK = 0;
		if (UsbFile.Time.Year > MyInfo.DataBaseTime.Year)
		  OK = 1;
		else if (UsbFile.Time.Year == MyInfo.DataBaseTime.Year)
		{
		  if (UsbFile.Time.Month > MyInfo.DataBaseTime.Month)
		    OK = 1;
		  else if (UsbFile.Time.Month == MyInfo.DataBaseTime.Month)
		    if (UsbFile.Time.Date >= MyInfo.DataBaseTime.Date)
		      OK = 1;
		}
		if (!OK)
		  return (0);*/
		//Get FATs:
        FirstClus = ((LgUns)FileBuf[j + 10] << 16) + FileBuf[j + 13];
        UsbFile.FileClusCnt = FAT32_GetFileClusters(USB_CF, (BPB_INFO *)&hbpb, FatBuf, FirstClus);
		Sec = UsbFile.FileClusCnt;
		Sec *= hbpb.TotBytesPerClus;
		if ((UsbFile.FileClusCnt < 1) || 
		    (UsbFile.FileSize > Sec) || 
		    (Sec > hbpb.TotBytesPerClus + UsbFile.FileSize))
		  return (0);
		
        //Head checking:
		Sec = hbpb.FirstDataSector + (FatBuf[0] - 2) * hbpb.SecPerClus;
		MB_TestUnit(0);
        MB_ReadCF(ABuf, Sec, 1);
		if ((ABuf[0] != GPS_FILE_ID_LO) || (ABuf[1] != GPS_FILE_ID_HI))
	      return (0);
		CRC = Calc_CRCWord(ABuf + 2, 16, 506);
		if (CRC != ABuf[255])
		  return (0);
		memcpy(Buf, ABuf + 2, 4);
		UsbFile.Time.Second = ABuf[2] & 0xFF;
        UsbFile.Time.Minute = ABuf[2] >> 8;
		UsbFile.Time.Hour = ABuf[3] & 0xFF;
		UsbFile.Time.Date = ABuf[3] >> 8;
		UsbFile.Time.Month = ABuf[4] & 0xFF;
		UsbFile.Time.Year = (ABuf[4] >> 8) + (ABuf[5] << 8);
		memcpy((void *)&UsbFile.Version, ABuf + 6, 6);
		UsbFile.StCnt = ABuf[12] + ((LgUns)ABuf[13] << 16);
		if (UsbFile.StCnt == 0)
		  return (0);
		UsbFile.RegCnt = ABuf[21];
		Sec = S29G_GetUnitQty(1, UsbFile.StCnt);
		tmp = S29G_GetUnitQty(0, UsbFile.StCnt);
		k = S29G_GetUnitQty(0, UsbFile.RegCnt);
		Sec <<= 5;//*32
		tmp <<= 8;//tmp <<= 7;
		tmp += (k << 8);
		UsbFile.RdCnt = ABuf[22];
		k = S29G_GetUnitQty(2, UsbFile.RdCnt);
		tmp += (k << 4);

		UsbFile.StAuxCnt = ABuf[23];
		k = S29G_GetUnitQty(3, UsbFile.StAuxCnt);
		tmp += (k << 6);

		Sec += tmp;
		if ((UsbFile.FileSize != Sec + 1024) && (UsbFile.FileSize != Sec + hbpb.TotBytesPerClus + 1024))
		  return (0);//WFL: the time fine an error of DataBase here
		//Tail checking:只读最后一个扇区
        Sec = hbpb.FirstDataSector + (FatBuf[UsbFile.FileClusCnt - 1] - 2) * hbpb.SecPerClus;
		k = UsbFile.FileSize >> 9;// div 512
		k = k % hbpb.SecPerClus;
		if (!k)
		  Sec += (hbpb.SecPerClus - 1);
		else
		  Sec += (k - 1);
		//Sec += (hbpb.SecPerClus - 1);
		MB_TestUnit(0);
        MB_ReadCF(ABuf, Sec, 1);
		if ((ABuf[0] != GPS_TAIL_ID_LO) || (ABuf[1] != GPS_TAIL_ID_HI))
		  return (0);
		CRC = Calc_CRCWord(ABuf + 2, 16, 506);
		if (CRC != ABuf[255])
		  return (0);
		for (k = 0; k < 3; k++)
		{
		  if (ABuf[2 + k] != Buf[k])
		    return (0);
		}
		if ((ABuf[5] & 0xFF) != (Buf[3] & 0xFF))
		  return (0);
		/*for (k = 0; k < 6; k++)
		{
		  if (ABuf[6 + k] != UsbFile.Version[k])
		    return (0);
		}*/
		if (ABuf[12] + ((LgUns)ABuf[13] << 16) != UsbFile.StCnt)
		  return (0);
		
        return (UsbFile.StCnt & 0xFFFF);
	  }
	}
  }
  return 0;
}

#pragma CODE_SECTION(HcApp_SaveDataBase, "FuncsMap2H0SARam")
Uns HcApp_SaveDataBase(void)
{
  Uns d, TotCnt;
  LgUns i, Sec, Offset;

  TotCnt = 0;
  Offset = 0;
  d = 0;
  while (TotCnt < UsbFile.FileClusCnt)
  {
    Sec = hbpb.FirstDataSector + (FatBuf[TotCnt] - 2) * hbpb.SecPerClus;
	MB_TestUnit(0);
	MB_ReadCF(UsbDataBuf + d, Sec, hbpb.SecPerClus);
	//write Flash here:
	d += (hbpb.SecPerClus << 8);//hbpb.SecPerClus * 256;
	if (d >= 32768)
	{
	  lld_memcpy((Uns *)S29G_BASE_ADDR, Offset, d, UsbDataBuf);
	  //此处校验:
	  S29G_FlashRead(CheckBuf, Offset, 32768);
	  for (i = 0; i < 32768; i++)
	    if (UsbDataBuf[i] != CheckBuf[i])
		  return (0);

	  Offset += d;
	  d = 0;
    }
	TotCnt++;
  }
  if (d > 0)
  {
    lld_memcpy((Uns *)S29G_BASE_ADDR, Offset, d, UsbDataBuf);
	//此处校验:
	S29G_FlashRead(CheckBuf, Offset, d);
	for (i = 0; i < d; i++)
	  if (UsbDataBuf[i] != CheckBuf[i])
	    return (0);
  }
  return (1);
}


//检测是否包含 BIOS 软件文件
//BIOS 程序文件限定在 32KWord( 64KByte) 以内
Uns HcApp_CheckBiosFile(void)
{
  LgUns Sec, FirstClus, Delta;
  Uns i, j, k, n, Cnt;
  //const Uns NameStr[] = {'G', 'P', 'S', '_', 'B','L', '1', '0'};

  FirstClus = 2;//根目录
  Cnt = FAT32_GetFileClusters(USB_CF, (BPB_INFO *)&hbpb, FatBuf2, FirstClus);
  for (i = 0; i < Cnt; i++)
  {
    //FileNames:
    Sec = hbpb.FirstDataSector + (FatBuf2[i] - 2) * hbpb.SecPerClus;
	MB_ReadCF(FileBuf, Sec, hbpb.SecPerClus);
	for (j = 0; j < (hbpb.TotBytesPerClus >> 1); j += 16)
	{
	  if ((FileBuf[j] & 0xFF) == 0x00)
	    break;
	  if (((FileBuf[j] & 0xFF) == 0x2E) || ((FileBuf[j] & 0xFF) == 0xE5))
	    continue;
	  for (k = 0; k < 5; k++)
      {
        UsbFile.FileName[k << 1] = (FileBuf[j + k] & 0xFF);
        UsbFile.FileName[(k << 1) + 1] = (FileBuf[j + k] >> 8);
      }
      UsbFile.FileName[10] = FileBuf[j + 5] & 0xFF;
	  if ((UsbFile.FileName[0] == 'G') && (UsbFile.FileName[1] == 'P') &&
	      (UsbFile.FileName[2] == 'S') && (UsbFile.FileName[3] == '_') &&
		  (UsbFile.FileName[4] == 'B') && (UsbFile.FileName[5] == 'L') &&
	      (UsbFile.FileName[8] == 'H') && (UsbFile.FileName[9] == 'E') && 
	      (UsbFile.FileName[10] == 'X'))//
	  {
	    UsbFile.FileSize = FileBuf[j + 14] + ((LgUns)FileBuf[j + 15] << 16);
	    if (UsbFile.FileSize > MAX_BIOS_FILE_SIZE)//BIOS文件(HEX)限制在128K
		  return (0);
        //Get FATs:
		FirstClus = ((LgUns)FileBuf[j + 10] << 16) + FileBuf[j + 13];
        UsbFile.FileClusCnt = FAT32_GetFileClusters(USB_CF, (BPB_INFO *)&hbpb, FatBuf, FirstClus);
		Sec = UsbFile.FileClusCnt;
		Sec *= hbpb.TotBytesPerClus;
		if ((UsbFile.FileClusCnt < 1) || 
		    ((UsbFile.FileSize > Sec) || (Sec > hbpb.TotBytesPerClus + UsbFile.FileSize)))
		  return (0);
        Delta = 0;
		for (n = 0; n < UsbFile.FileClusCnt; n++)
        {
          //FileNames:
          Sec = hbpb.FirstDataSector + (FatBuf[n] - 2) * hbpb.SecPerClus;
	      MB_ReadCF(BiosFileBuf + Delta, Sec, hbpb.SecPerClus);
		  Delta += (hbpb.TotBytesPerClus >> 1);
		}
		return (1);
	  }
	}
  }
  return 0;
}

//检测 USB device 是否包含 GpsBak00.gps 文件；如果有，将数据库存入该文件
Uns HcApp_CheckBackupFile(void)
{
  LgUns Sec, FirstClus;
  Uns i, j, k, Cnt, OK;
  const Uns NameStr[11] = {'G', 'p', 's', 'B', 'a', 'k', '0', '0', 'G', 'P', 'S'};

  FirstClus = 2;//根目录
  Cnt = FAT32_GetFileClusters(USB_CF, (BPB_INFO *)&hbpb, FatBuf2, FirstClus);
  for (i = 0; i < Cnt; i++)
  {
    //FileNames:
    Sec = hbpb.FirstDataSector + (FatBuf2[i] - 2) * hbpb.SecPerClus;
	MB_ReadCF(FileBuf, Sec, hbpb.SecPerClus);
	for (j = 0; j < (hbpb.TotBytesPerClus >> 1); j += 16)
	{
	  if ((FileBuf[j] & 0xFF) == 0x00)
	    break;
	  if (((FileBuf[j] & 0xFF) == 0x2E) || ((FileBuf[j] & 0xFF) == 0xE5))
	    continue;
	  for (k = 0; k < 5; k++)
      {
        UsbFile.FileName[k << 1] = (FileBuf[j + k] & 0xFF);
        UsbFile.FileName[(k << 1) + 1] = FileBuf[j + k] >> 8;
      }
      UsbFile.FileName[10] = FileBuf[j + 5] & 0xFF;
	  OK = 1;
	  for (k = 0; k < 11; k++)
	  {
	    if (UsbFile.FileName[k] != NameStr[k])
		{
		  OK = 0;
		  break;
		}
	  }
	  if (OK)//
	  {
	    UsbFile.FileSize = FileBuf[j + 14] + ((LgUns)FileBuf[j + 15] << 16);
		if (UsbFile.FileSize != MyInfo.XFlashSize - 0x20000L)
		//if (UsbFile.FileSize > MyInfo.XFlashSize)
		  return (0);
		//该文件大小应该是 512 的整数倍
		if (((UsbFile.FileSize >> 9) << 9) != UsbFile.FileSize)
		  return (0);
		//Get FATs:
        FirstClus = ((LgUns)FileBuf[j + 10] << 16) + FileBuf[j + 13];
        UsbFile.FileClusCnt = FAT32_GetFileClusters(USB_CF, (BPB_INFO *)&hbpb, FatBuf, FirstClus);
		Sec = UsbFile.FileClusCnt;
		Sec *= hbpb.TotBytesPerClus;
		if ((UsbFile.FileClusCnt < 1) || 
		    (UsbFile.FileSize > Sec) || 
		    (Sec > hbpb.TotBytesPerClus + UsbFile.FileSize))
		  return (0);
		
		
        return (UsbFile.FileClusCnt);
	  }
	}
  }
  return 0;
}

extern DATA_BASE_INFO DataBase;
Uns HcApp_SaveDB2Usb(void)
{
  Uns i, j, k, Delta, Cnt32k, Cnt, Remain;
  LgUns Sec, Offset;
  

  Offset = MyInfo.DBStationOffset;
  Sec = S29G_GetUnitQty(0, DataBase.StCnt) << 6;
  Sec += 256;
  Offset += Sec;
  Cnt32k = Offset >> 15;
  if (((LgUns)Cnt32k << 15) != Offset)
	Remain = Offset - ((LgUns)Cnt32k << 15);
  else
    Remain = 0;
  //32K word 包含多少个 Cluster：
  Cnt = 32768 / (hbpb.TotBytesPerClus >> 1);
  Offset = 0;
  j = 0;
  for (i = 0; i < Cnt32k; i++)
  {
    S29G_FlashRead(UsbDataBuf, Offset, 32768);
	Offset += 32768;
    k = 0;
	Delta = 0;
	while (k < Cnt)
    {
	  MB_WriteCF(UsbDataBuf + Delta, FatBuf[j], hbpb.SecPerClus);
	  Delta += (hbpb.TotBytesPerClus >> 1);
	  k++;
	  j++;
	  if (!Hc_XDevInfo.DevOK)
	    break;
	}
	if (!Hc_XDevInfo.DevOK)
	    break;
  }
  if (Hc_XDevInfo.DevOK && Remain)
  {
    S29G_FlashRead(UsbDataBuf, Offset, Remain);
	Offset += Remain;
	Cnt = Remain / (hbpb.TotBytesPerClus >> 1);
	Remain -= (Cnt * (hbpb.TotBytesPerClus >> 1));
    k = 0;
	Delta = 0;
	while (k < Cnt)
    {
	  MB_WriteCF(UsbDataBuf + Delta, FatBuf[j], hbpb.SecPerClus);
	  Delta += (hbpb.TotBytesPerClus >> 1);
	  k++;
	  j++;
	  if (!Hc_XDevInfo.DevOK)
	    break;
	}
	if (Hc_XDevInfo.DevOK && Remain)
	{
	  S29G_FlashRead(UsbDataBuf, Offset, Remain);
	  MB_WriteCF(UsbDataBuf, FatBuf[j], hbpb.SecPerClus);
	}
  }
  return (1);
}















